package quartz.controller;

import org.assertj.core.util.Lists;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import quartz.entity.BaseEntity;
import quartz.service.BaseService;
import quartz.util.SpringUtil;

import java.beans.Introspector;
import java.lang.reflect.ParameterizedType;
import java.util.List;

public abstract class BaseController<T extends BaseEntity, ID> {
  @SuppressWarnings("unchecked")
  private Class<T> getTClass() {
    return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
  }

  protected String getServiceBeanName () {
    return Introspector.decapitalize(String.format("%sService", this.getTClass().getSimpleName()));
  }

  @SuppressWarnings("unchecked")
  protected BaseService<T, ID> getService() {
    return (BaseService<T, ID>) SpringUtil.getBean(this.getServiceBeanName());
  }

  @GetMapping
  ResponseEntity<Page<T>> getAll (
    @RequestParam(defaultValue = "-1")Integer page,
    @RequestParam(defaultValue = "-1")Integer size,
    @RequestParam(defaultValue = "lastModifiedDate") String sortBy,
    @RequestParam(defaultValue = "DESC") Sort.Direction sortDirection
  ) {
    Sort sort = Sort.by(new Sort.Order(sortDirection, sortBy));
    if (page < 0 || size < 0) {
      List<T> content = Lists.newArrayList(getService().findAll(sort));
      ResponseEntity.ok(new PageImpl<T>(
        content,
        PageRequest.of(page, size, sort),
        content.size()
      ));
    }
    return ResponseEntity.ok(getService().findAll(PageRequest.of(page - 1, size, sort)));
  }

  @GetMapping("/{id}")
  ResponseEntity<T> getById (@PathVariable ID id) {
    return ResponseEntity.ok(getService().findById(id));
  }

  @PostMapping
  ResponseEntity<T> save (@RequestBody T t) {
    return ResponseEntity.ok(getService().save(t));
  }

  @DeleteMapping("/{id}")
  ResponseEntity deleteById (@PathVariable ID id) {
    getService().deleteById(id);
    return new ResponseEntity(HttpStatus.OK);
  }
}
